<?php

namespace app\push\controller;

use think\Db;
use Workerman\Lib\Timer;
use Workerman\Worker;
use Workerman\Connection\TcpConnection;

class Workerman
{
    protected $HEARTBEAT_TIME = '60';

    public function __construct()
    {
        global $worker;
        // 创建一个Worker监听2346端口，使用websocket协议通讯
        $worker = new Worker("websocket://worker.lizaonet.com:2346");

        // 启动1个进程对外提供服务
        $worker->count = 1;

        // 新增加一个属性，用来保存uid到connection的映射(uid是用户id或者客户端唯一标识)
        $worker->uidConnections = [];

        $worker->onConnect = function ($connection) {
            $connection->send('连接成功，客户ID：' . $connection->id);
        };

        $worker->onMessage = function (TcpConnection $connection, $data) {
            $data = json_decode($data, true);

            $connection->lastMessageTime = time();
            global $worker;

            if (!isset($connection->uid)) {
                // $data['user_id'] 来自于客户端发送过来的数据，可以来自于数据库，比如此处的user_id就是数据库中的用户id
                $connection->uid = $data['user_id'];

                // 判断是否是客服，存储一个标识is_contact
                $is_admin = Db::name('user')->where(['id' => $data['user_id']])->value('is_admin');
                $connection->is_contact = $is_admin;

                // 将长时间未通信提醒状态设置成未提醒状态
                $connection->is_remind_will_over_time = false;

                /**
                 * 保存uid到connection的映射，这样可以方便的通过uid查找connection，
                 * 实现针对特定uid推送数据
                 **/
                $worker->uidConnections[$connection->uid] = $connection;
            }

            $this->sendMessage($connection, $data);
        };

        $worker->onWorkerStart = function ($connection) {
            // 开启一个内部端口，方便内部系统推送数据，Text协议格式 文本+换行符
            $inner_text_worker = new \Workerman\Worker('Text://127.0.0.1:5678');
            $inner_text_worker->onMessage = function ($connection, $buffer) {
                $buffer = json_decode($buffer, false);
                $this->sendMessage($connection, $buffer);
            };
            $inner_text_worker->listen();
            Timer::add(
                5, function () use ($connection) {
                $time_now = time();
                foreach ($connection->connections as $connection) {
                    // 有可能该connection还没收到过消息，则lastMessageTime设置为当前时间
                    if (empty($connection->lastMessageTime)) {
                        $connection->lastMessageTime = $time_now;
                        continue;
                    }

                    // dump('uid：' . $connection->uid . '；is_contact：' . $connection->is_contact . '；is_remind_will_over_time：' . ($connection->is_remind_will_over_time ? 'true' : 'false'));

                    // 上次通讯时间间隔大于心跳间隔，则认为客户端已经下线，关闭连接
                    if ($time_now - $connection->lastMessageTime > $this->HEARTBEAT_TIME) {

                        // 告知用户通话已结束
                        $close_user_data = [
                            'type' => 'close',
                            'msg' => '本次通话已结束'
                        ];
                        $connection->send(json_encode($close_user_data, JSON_UNESCAPED_UNICODE));
                    } else if ($time_now - $connection->lastMessageTime > $this->HEARTBEAT_TIME - 20 && $connection->uid) {
                        /**
                         * 查询是否是后台管理人员
                         * 后台管理人员利用心跳防止断线
                         * */
                        $is_contact = $connection->is_contact;
                        if ($is_contact == 1) {
                            $connection->lastMessageTime = $time_now;
                            $connection->send('后台管理人员心跳默认消息');
                        } else if ($connection->is_remind_will_over_time === false) {
                            $connection->is_remind_will_over_time = true;

                            $will_data = [
                                'type' => 'will_over_time',
                                'msg' => '长时间未通信，1分钟后结束通话'
                            ];
                            $connection->send(json_encode($will_data, JSON_UNESCAPED_UNICODE));
                        }
                    }
                }
            }
            );
        };

        $worker->onClose = function ($connection) {

        };

        $worker->onError = function ($connection, $code, $msg) {
            echo "error $code $msg\n";
        };

        worker::runAll();
    }

    public function sendMessage($connection, $data)
    {
        Db::startTrans();

        try {
            global $worker;

            switch ($data['type']) {
                case 'user_connect':
                    // 用户连接成功

                    /*$username = Db::name('user')->where(['id' => $data['user_id']])->value('username');

                    $data = [
                        'type' => 'obj',
                        'msg' => $username . '，请问你有什么问题呢？'
                    ];
                    $connection->send(json_encode($data, JSON_UNESCAPED_UNICODE));*/
                    break;
                case 'contact_send':
                    // 客服发送消息
                    $contact_id = $data['contact_id'];// 客服id
                    $user_id = $data['user_id'];      // 用户id
                    $msg = $data['msg'];              // 消息内容

                    if (!empty($worker->uidConnections[$user_id])) {
                        // 用户在线
                        $insert_data = [
                            'from_uid' => $contact_id,
                            'to_uid' => $user_id,
                            'msg' => $msg,
                            'is_read' => 1,
                            'create_time' => time()
                        ];
                        Db::name('chat')->insert($insert_data);

                        $avatar = Db::name('user')->where(['id' => $contact_id])->value('avatar');
                        // 发送消息
                        $data = [
                            'type' => 'contact_send',
                            'avatar' => $avatar,
                            'msg' => $msg
                        ];
                        $worker->uidConnections[$user_id]->send(json_encode($data, JSON_UNESCAPED_UNICODE));
                    }

                    break;
                case 'user_send':
                    // 用户发送消息

                    // 客服ID
                    $user_id = $data['user_id'];
                    $contact_id = Db::name('chat')->where(['from_uid' => $user_id, 'is_over' => 0])->order('create_time desc')->value('to_uid');
                    $contact_id = $contact_id ? : 0;

                    $insert_data = [
                        'from_uid' => $user_id,
                        'to_uid' => $contact_id,
                        'msg' => $data['msg'],
                        'create_time' => time()
                    ];

                    if (!empty($worker->uidConnections[$contact_id])) {
                        // 已接入对应客服
                        $insert_data['is_read'] = 1;

                        // 发送消息
                        $msg_data = [
                            'type' => 'user_send',
                            'user_id' => $user_id,
                            'username' => $data['username'],
                            'avatar' => doAvatar($data['avatar']),
                            'msg' => $data['msg']
                        ];
                        $worker->uidConnections[$contact_id]->send(json_encode($msg_data, JSON_UNESCAPED_UNICODE));
                    } else {
                        // 未接入对应客服
                        $insert_data['is_read'] = 0;

                        if ($worker->uidConnections) {
                            $msg_data = [
                                'type' => 'wait_link',
                                'user_id' => $user_id,
                                'username' => $data['username'],
                                'avatar' => doAvatar($data['avatar']),
                            ];
                            foreach ($worker->uidConnections as $v) {
                                if ($v->is_contact == 1) {
                                    // 发送待接入消息给客服
                                    $worker->uidConnections[$v->uid]->send(json_encode($msg_data, JSON_UNESCAPED_UNICODE));
                                }
                            }
                        }
                    }
                    Db::name('chat')->insert($insert_data);

                    $worker->uidConnections[$user_id]->is_remind_will_over_time = false;
                    break;
                case 'link_remind';
                    $user_id = $data['user_id'];
                    $contact_id = $data['contact_id'];

                    if ($worker->uidConnections) {
                        foreach ($worker->uidConnections as &$v) {
                            // 身份是客服 && 该客服不是主动接入的客服
                            if ($v->is_contact == 1 && $v->uid != $contact_id) {
                                // 发送消息给其他客服
                                $msg_data = [
                                    'type' => 'link_remind',
                                    'user_id' => $user_id,
                                    'msg' => '用户ID：' . $user_id . '；已被其他客服接入'
                                ];
                                $worker->uidConnections[$v->uid]->send(json_encode($msg_data, JSON_UNESCAPED_UNICODE));
                            }
                        }
                    }
                    break;
                case 'user_close':
                    $user_id = $data['user_id'];
                    $contact_id = Db::name('chat')->where(['from_uid' => $user_id, 'is_over' => 0])->order('create_time desc')->value('to_uid');
                    $contact_id = $contact_id ? : 0;

                    // 发送断开连接消息给客服
                    $msg_data = [
                        'type' => 'user_close',
                        'user_id' => $user_id,
                        'msg' => '用户连接已断开'
                    ];
                    $worker->uidConnections[$contact_id]->send(json_encode($msg_data, JSON_UNESCAPED_UNICODE));

                    // 删除断开连接用户
                    unset($worker->uidConnections[$user_id]);

                    break;
                default:
                    $connection->send('默认消息');
                    break;
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            echo $e;
        }
    }
}
